package airAgent.group2;

import airAgent.group2.util.TicketManagement;
import airAgent.group2.util.Util;
import ontology.ontology.Money;
import ontology.ontology.Direction;
import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.*;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.SimpleBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.content.onto.*;
import jade.content.onto.basic.Action;

import ontology.ontology.AirAgentOntology;
import ontology.ontology.BuyTicket;
import ontology.ontology.CancelTicket;
import ontology.ontology.CheckTicketPrice;
import ontology.ontology.InformDate;

import ontology.ontology.Ticket;


public class Airline2 extends Agent {
	private static final long serialVersionUID = 1L;
	private Codec codec = new SLCodec();
	private boolean start, end;
    private	Ontology ontology = AirAgentOntology.getInstance();
	private AID bank, timer;
	private int day;
	private boolean subscribed=false;
	private boolean subscribeNotRequested=true;
	private TicketManagement monthlyTickets;
	private float dailyFuelCost;
	private int numTicketsSold=0;
	private int numTicketsCancelled=0;

	protected void setup() {
		Util.register(this.getName(), Util.AIRLINE, this);

		System.out.println("Airline " + getLocalName() + " has entered into the system");
		// Register of the codec and the ontology to be used in the
		// ContentManager
		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);
		
		start=false;
		end=false;
		
		monthlyTickets = new TicketManagement();

		// CREATE ACCOUNT AND SUBSCRIBE TO TIMER
		addBehaviour(new SimpleBehaviour(this) {
			private static final long serialVersionUID = 1L;
			private boolean done;

			public void action() {
				
				DFAgentDescription dfd = new DFAgentDescription();
				ServiceDescription sd = new ServiceDescription();
				DFAgentDescription dfd2 = new DFAgentDescription();
				ServiceDescription sd2 = new ServiceDescription();
				
				sd.setType(Util.BANK);
				dfd.addServices(sd);
				
				sd2.setType(Util.TIMER);
				dfd2.addServices(sd2);

				DFAgentDescription[] res = new DFAgentDescription[1];
				DFAgentDescription[] res2 = new DFAgentDescription[1];
				try {
					res = DFService.search(myAgent, dfd);
					res2 = DFService.search(myAgent, dfd2);
				} catch (FIPAException e) {
					e.printStackTrace();
				}
				if (res.length > 0) {
					if (subscribed){
						bank = (AID) res[0].getName();
						Util.CreateAccount(myAgent, bank, codec, ontology);
						done = true;
					}
					else{
						if(res2.length > 0 ) {
							if(subscribeNotRequested){
								timer = (AID) res2[0].getName();
								Util.SubscribeTimer(myAgent, timer, codec, ontology);
								subscribeNotRequested=false;
							}
						} else {
							System.out.println("Failed to find the Timer");
						}
					}
				} else {
					System.out.println("Failed, retrying in 5 seconds...");
					doWait(5000);
				}
			
			}

			@Override
			public boolean done() {
				return done;
			}
		});

		addBehaviour(new CyclicBehaviour(this) {
			private static final long serialVersionUID = 1L;

			public void action() {
//				ACLMessage msg = receive(MessageTemplate
//						.MatchPerformative(ACLMessage.INFORM));
				ACLMessage msg = receive (MessageTemplate.MatchLanguage(codec.getName()));
				
//				ACLMessage msg = receive (MessageTemplate.MatchAll());
				
/*				ACLMessage msg = receive(MessageTemplate
						.and(MessageTemplate.MatchLanguage(codec.getName()),
								MessageTemplate.MatchOntology(ontology
										.getName())));
*/				
				if (msg != null) {
					 ContentElement ce = null;
					if (msg.getPerformative() == ACLMessage.INFORM) {
						//if (ce instanceof Action) {
							//Action agAction = (Action) ce;
							//Concept con = agAction.getAction();
							if (msg.getProtocol().equals(AirAgentOntology.CREATEACCOUNT))
								//System.out.println(myAgent.getLocalName()+ " Account OK");
								;
							else if (msg.getProtocol().equals(AirAgentOntology.DEPOSIT))
								//System.out.println(myAgent.getLocalName() + " Deposit OK");
								;
							else if (msg.getProtocol().equals(AirAgentOntology.WITHDRAWN))
								//System.out.println(myAgent.getLocalName()		+ " Withdraw OK");
								;
							else if (msg.getProtocol().equals(AirAgentOntology.INFORMDATE)){
								try {
									ce = getContentManager().extractContent(msg);
								} catch (Exception e) {
									e.printStackTrace();
								}
								if (ce instanceof Action) {
									Action agAction = (Action) ce;
									Concept con = agAction.getAction();
									if (con instanceof InformDate){
										day= ((InformDate) con).getDate();
										if(day!= 1){
											dailyFuelCost=(float)(Util.FUEL_COST * monthlyTickets.getTotalNumberOfSoldTicketsForDay(day-1));
											if(dailyFuelCost > 0)
												Util.Withdraw(myAgent, bank, codec, ontology, dailyFuelCost);
											System.out.println(myAgent.getLocalName() +" has withdrawn daily fuel cost from the bank: " + dailyFuelCost);
										}
										System.out.println(myAgent.getLocalName() + " received the date: "
										+ day);
									}
								}
							}
							else if (msg.getProtocol().equals(AirAgentOntology.STARTSIMULATION)){
								//System.out.println(myAgent.getLocalName() + " received START");
								start=true;
							}
							else if (msg.getProtocol().equals(AirAgentOntology.ENDOFSIMULATION)){
								//System.out.println(myAgent.getLocalName() + " received END");
								
								float subsidyAmount = Util.calculateSubsidy(monthlyTickets);
								if(subsidyAmount>0){
									Util.Deposit(myAgent, bank, codec, ontology, subsidyAmount);
									System.out.println(myAgent.getLocalName() +" has deposited Subsidy bonus to the bank: " + subsidyAmount);
								}else
									; //System.out.println("No subsidy bonus!");
								
								float otherCosts = Util.calculateOtherCosts(monthlyTickets);
								Util.Withdraw(myAgent, bank, codec, ontology, otherCosts);
								System.out.println(myAgent.getLocalName() +" has Withdrawn Airport taxes, Heli maintenance and pilot salary the bank: " + otherCosts);
								
								int numFlights=Util.calculateTotalFlightsPerformed(monthlyTickets);
								System.out.println("-_-_-_-_-_ RESULT MONITOR -_-_-_-_-_");
								System.out.println("Number of Flights Performed: " + numFlights);
								System.out.println("Number of Flights Cancelled: " + (Util.SIMULATION_DAYS * 2 - numFlights));
								System.out.println("Number of Tickets Sold: " + numTicketsSold);
								System.out.println("Number of Tickets Cancelled: " + numTicketsCancelled);
								end=true;
							}
							else
								System.out.println("Unidentified inform to the airline");
							
						//}
					}else if (msg.getPerformative() == ACLMessage.QUERY_REF){
						
						try {
							ce = getContentManager().extractContent(msg);
						} catch (UngroundedException e) {
							e.printStackTrace();
						} catch (CodecException e) {
							e.printStackTrace();
						} catch (OntologyException e) {
							e.printStackTrace();
						}
						//System.out.println(myAgent.getLocalName() +" Received Price Request");
						if (ce instanceof Action) {
							Action agAction = (Action) ce;
							Concept con = agAction.getAction();
							if (con instanceof CheckTicketPrice){
								Ticket ticket = Util.initializeTicket(myAgent.getAID(),msg.getSender(), ((CheckTicketPrice) con).getTicketDate(), ((CheckTicketPrice) con).getTicketDirection(), new Money(), ((CheckTicketPrice) con).getTicketSeats(), false);
								if(ticket.getTicketDate()<= Util.SIMULATION_DAYS)
									Util.ReturnTicketPrice(myAgent,msg.getSender(), codec, ontology, ticket, monthlyTickets, day);
 							}
						}
							
					}else if (msg.getPerformative() == ACLMessage.REQUEST) {
						
						try {
							ce = getContentManager().extractContent(msg);
						} catch (UngroundedException e1) {
							e1.printStackTrace();
						} catch (CodecException e1) {
							e1.printStackTrace();
						} catch (OntologyException e1) {
							e1.printStackTrace();
						}
						if (ce instanceof Action) {
							Action agAction = (Action) ce;
							Concept con = agAction.getAction();
							
							ACLMessage reply = msg.createReply();
							reply.setLanguage(codec.getName());
							reply.setOntology(ontology.getName());
							if (con instanceof BuyTicket) {
								BuyTicket ctp = (BuyTicket)con;
								Ticket ticket = Util.initializeTicket(myAgent.getAID(), msg.getSender(), ctp.getTicketDate(), ctp.getTicketDirection(), new Money(), ctp.getTicketSeats(), true);   
								
							   System.out.println(myAgent.getLocalName()+ ": Client " + msg.getSender().getLocalName() + " buying " +  ctp.getTicketSeats() +" seats in date " + ctp.getTicketDate() + " in direction " + (ctp.getTicketDirection().getValue() ? "Barajas - Montegancedo" : "Montegancedo - Barajas"));
							   ACLMessage reply_ag = msg.createReply();
							   reply_ag.setLanguage(codec.getName());
							   reply_ag.setOntology(ontology.getName());
							   reply_ag.setProtocol(AirAgentOntology.BUYTICKET);
							   if(day <= ticket.getTicketDate()){
								   if(ctp.getTicketSeats() <= monthlyTickets.getTotalNumberOfAvailableSeats(ticket))
								   {
								       reply.setPerformative(ACLMessage.INFORM);
								       Direction direction = new Direction();
								       direction.setValue(ctp.getTicketDirection().getValue());
								       System.out.println(myAgent.getLocalName() +": Ticket sold to "+ msg.getSender().getLocalName());
								       Util.Deposit(myAgent, bank, codec, ontology,ticket.getTicketPrice().getValue() * ticket.getTicketSeats());
								       monthlyTickets.sellTicket(msg.getSender(), ticket);
								       numTicketsSold += ticket.getTicketSeats();
								   } else
								   {
								       reply.setPerformative(ACLMessage.REFUSE);
								       System.out.println(myAgent.getLocalName() + ": No available ticket for" + msg.getSender().getLocalName());
								   }
							   }
							   else
							   {
							       reply.setPerformative(ACLMessage.REFUSE);
							       System.out.println(myAgent.getLocalName() + ": Ticket cannot be sold as today is later than ticket date for client: " + msg.getSender().getLocalName() + " today:"+ day + " ticket date:" + ticket.getTicketDate());
							   }
							   myAgent.send(reply);
	                       }
							 
						else if (con instanceof CancelTicket) {	
							  CancelTicket ct = (CancelTicket)con;
							  Ticket ticket = Util.initializeTicket(myAgent.getAID(), msg.getSender(), ct.getTicketDate(), ct.getTicketDirection(), new Money(), ct.getTicketSeats(), false);
							  
							  System.out.println(myAgent.getLocalName()+ ": Client " + msg.getSender().getLocalName() + " asks to cancel " +  ct.getTicketSeats() +" seats in date " + ct.getTicketDate() + " in direction " + (ct.getTicketDirection().getValue() ? "Barajas - Montegancedo" : "Montegancedo - Barajas"));
                              ACLMessage reply_cancel = msg.createReply();
                              reply_cancel.setLanguage(codec.getName());
                              reply_cancel.setOntology(ontology.getName());
                              reply_cancel.setProtocol(AirAgentOntology.CANCELTICKET);
                           //   Direction direction = new Direction();
                           //   direction.setValue(ct.getTicketDirection().getValue());
                             
                              //if(monthlyTickets.isTicketSoldToClient(msg.getSender(),ticket))
                              //{
                                     reply.setPerformative(ACLMessage.INFORM);
                                     Util.Withdraw(myAgent, bank, codec, ontology, Util.retrieveTicketPrice(ticket, monthlyTickets));		//Find Price here ALID
                                     monthlyTickets.cancelTicketSold(msg.getSender(), ticket);
                                     System.out.println((new StringBuilder(String.valueOf(myAgent.getLocalName()))).append(": Ticket cancelled for ").append(msg.getSender().getLocalName()).toString());
                                     numTicketsCancelled += ticket.getTicketSeats();
                                   
                          /*    } else
                              {
                                  reply.setPerformative(ACLMessage.REFUSE);
                                  System.out.println( myAgent.getLocalName() +": The ticket cannot be cancelled, it is not owned by this customer:"+ msg.getSender().getLocalName());
                                  
                              }	*/
                              myAgent.send(reply);
							}
						}
					}else if (msg.getPerformative() == ACLMessage.AGREE) {
						//System.out.println(myAgent.getLocalName() + " succesfully subscribed");
						subscribed=true;
					}
				
				}
				else
					;
					//System.out.println("Null message received by the airline");
			}
		});

	}

}
